package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.product.service.TestService;
import org.redisson.api.RLock;
import org.redisson.api.RReadWriteLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.data.redis.core.script.RedisScript;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Arrays;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author atguigu-mqx
 */
@Service
public class TestServiceImpl implements TestService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    //  获取到redisson 的客户端
    @Autowired
    private RedissonClient redissonClient;

    //  使用redisson 实现！
    @Override
    public void testLock() {
        //  基本操作、上锁 ，业务逻辑，解锁！
        RLock lock = redissonClient.getLock("myLock");
        //  上锁：
        lock.lock(10,TimeUnit.SECONDS);
        try {
            //  获取数据
            String num = redisTemplate.opsForValue().get("num");
            //  判断是否能够获取到数据
            if (StringUtils.isEmpty(num)){
                return;
            }
            //  int i = 1/0;
            //  转换数据类型
            int numValue = Integer.parseInt(num);
            //  将数据放回缓存！
            redisTemplate.opsForValue().set("num",String.valueOf(++numValue));
        } catch (NumberFormatException e) {
            e.printStackTrace();
        } finally {
            //  解锁：
            lock.unlock();
        }

    }

    @Override
    public String readLock() {
        //  创建对写锁对象
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("anyRWLock");
        //  获取到读锁：
        rwlock.readLock().lock(10,TimeUnit.SECONDS);

        //  读取的内容：
        String msg = this.redisTemplate.opsForValue().get("msg");

        //  不写解锁！ 让其自动解锁！
        return msg;
    }

    @Override
    public String writeLock() {
        //  写入的时候，写一个key 为 msg 的消息！
        //  创建对写锁对象
        RReadWriteLock rwlock = redissonClient.getReadWriteLock("anyRWLock");
        //  获取到写锁
        rwlock.writeLock().lock(10,TimeUnit.SECONDS);
        //  写入数据
        this.redisTemplate.opsForValue().set("msg",UUID.randomUUID().toString());
        //  不写解锁！ 让其自动解锁！

        return "写入数据完成.....";
    }
    //  private RedisTemplate redisTemplate;

    /*@Override
    public void testLock() {
        *//*
        1.  在缓存中存储一个数据 num = 0； set num 0
        2.  获取缓存中的num 数据
            true:   对这个num + 1的操作！ 放入缓存！
            false:  直接返回！
         *//*
        //  setnx lock ok
        //  Boolean flag = redisTemplate.opsForValue().setIfAbsent("lock", "atguigu");

        //  set skuLock ok ex 10 nx 具有原子性！
        String uuid = UUID.randomUUID().toString();
        Boolean flag = redisTemplate.opsForValue().setIfAbsent("lock", uuid,3, TimeUnit.SECONDS);
        //  flag = ture :表示上锁成功，否则上锁失败！
        if (flag){
            //  获取数据
            String num = redisTemplate.opsForValue().get("num");
            //  判断是否能够获取到数据
            if (StringUtils.isEmpty(num)){
                return;
            }
            //  int i = 1/0;
            //  转换数据类型
            int numValue = Integer.parseInt(num);
            //  将数据放回缓存！
            redisTemplate.opsForValue().set("num",String.valueOf(++numValue));
            //  释放锁！ 虽然加了过期时间，但是释放锁的代码也要有！
            //            if (uuid.equals(redisTemplate.opsForValue().get("lock"))){
            //                //  如果线程的内存模型中的uuid 与 redis 的num 数据值一样，则删除锁！否则不删！
            //                redisTemplate.delete("lock");
            //            }
            //  准备一个lua 脚本
            String script = "if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end";
            //  执行lua 脚本
            DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
            redisScript.setScriptText(script);
            redisScript.setResultType(Long.class);
            //  第一个参数，lua脚本对象 ，第二个参数 key， 第三个就是value
            redisTemplate.execute(redisScript, Arrays.asList("lock"),uuid);

        }else {
            //  没有获取到锁的人！ 自旋！
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            testLock();
        }
    }*/
}
